<?php

	namespace org\tekuna\test\core;

	use \PHPUnit_Framework_TestCase;

	use org\tekuna\core\context\Context;
	use org\tekuna\core\context\ContextException;

	use org\tekuna\test\base\ClassToTestAutoloading;


	class ContextTest extends PHPUnit_Framework_TestCase {

		public function testSetObject() {

			$objContext = new Context();
			$objX = new ClassToTestAutoloading();

			// there is no testName object
			$this -> assertFalse($objContext -> hasObject("testName"));

			// when try to get this object an exception will be thrown
			try {

				$objContext -> getObject('testName');
				$this -> fail("There should be thrown a ContextException");
			}
			catch (ContextException $objCE) {
				// this is correct
			}

			// set the object in the context
			$objContext -> setObject("testName", $objX);

			// now there is a testName object
			$this -> assertTrue($objContext -> hasObject("testName"));

			// and nothing goes wrong when requesting that object
			$objY = $objContext -> getObject("testName");

			// and the type is not null and of the desired type
			$this -> assertFalse($objY === null);
			$this -> assertTrue($objY instanceof ClassToTestAutoloading);
		}


		public function testNullObject() {

			// put an object into the context
			$objContext = new Context();
			$objContext -> setObject("testName", new ClassToTestAutoloading());
			$this -> assertTrue($objContext -> hasObject("testName"));

			// set value NULL for this object
			$objContext -> setObject("testName", null);

			// the field is still set
			$this -> assertTrue($objContext -> hasObject("testName"));

			// and it has a real null
			$this -> assertNull($objContext -> getObject("testName"));
		}


		public function testRemoveObject() {

			// put an object into the context
			$objContext = new Context();
			$objContext -> setObject("testName", new ClassToTestAutoloading());
			$this -> assertTrue($objContext -> hasObject("testName"));

			// remove the object
			$objContext -> removeObject("testName");

			// object doesn't exist anymore
			$this -> assertFalse($objContext -> hasObject("testName"));

			// remove not existing object
			$this -> assertFalse($objContext -> hasObject("nonExistingObject"));
			$objContext -> removeObject("nonExistingObject");
			$this -> assertFalse($objContext -> hasObject("nonExistingObject"));
		}


		public function testGetAllObjects() {

			$objContext = new Context();

			$objContext -> setObject("testName", new ClassToTestAutoloading());
			$objContext -> setObject("testName2", new ClassToTestAutoloading());

			$arrAllObjects = $objContext -> getAllObjects();

			$this -> assertEquals(2, count($arrAllObjects));
			$this -> assertEquals('org\tekuna\test\base\ClassToTestAutoloading', get_class($arrAllObjects['testName']));
			$this -> assertEquals('org\tekuna\test\base\ClassToTestAutoloading', get_class($arrAllObjects['testName2']));
		}


		public function testMagicMethods() {

			$objContext = new Context();

			// there is no test object
			$this -> assertFalse($objContext -> hasTestObject());

			// akquiring a non existing object results in the known exception
			try {

				$objContext -> getTestObject();
				$this -> fail("There should be thrown a ContextException");
			}
			catch (ContextException $objCE) {
				// this is correct
			}

			// now the object exists in the context
			$objContext -> setTestObject(new ClassToTestAutoloading());
			$this -> assertTrue($objContext -> hasTestObject());
			$this -> assertTrue($objContext -> hasObject("TestObject"));

			// get it out
			$objY = $objContext -> getTestObject();

			// and the type is not null and of the desired type
			$this -> assertFalse($objY === null);
			$this -> assertTrue($objY instanceof ClassToTestAutoloading);

			// remove the test object
			$objContext -> removeTestObject();
			$this -> assertFalse($objContext -> hasTestObject());
			$this -> assertFalse($objContext -> hasObject("TestObject"));
		}


		private function doTestRoundtrip(Context $objContext, $mVariable) {

			// object non existent
			$this -> assertFalse($objContext -> hasVariableTest());

			// set the object
			$objContext -> setVariableTest($mVariable);

			// now it exists in the context
			$this -> assertTrue($objContext -> hasVariableTest());

			// check for type equality of this object
			$this -> assertTrue($mVariable === $objContext -> getVariableTest());

			// remove the object
			$objContext -> removeVariableTest();

			// now it does not exist any more
			$this -> assertFalse($objContext -> hasVariableTest());
		}


		public function testVariableTypes() {

			$objContext = new Context();
			$this -> doTestRoundtrip($objContext, null);
			$this -> doTestRoundtrip($objContext, true);
			$this -> doTestRoundtrip($objContext, false);
			$this -> doTestRoundtrip($objContext, 42);
			$this -> doTestRoundtrip($objContext, 8.15);
			$this -> doTestRoundtrip($objContext, 'my special string');
			$this -> doTestRoundtrip($objContext, array(1, 2, 3));
			$this -> doTestRoundtrip($objContext, new ClassToTestAutoloading());

			$hFile = fopen(__FILE__, 'r');
			$this -> doTestRoundtrip($objContext, $hFile);
			fclose($hFile);
		}


		public function testToString() {

			$objContext = new Context();
			$objContext -> setATest(1234);
			$objContext -> setAnotherTest('asdf');

			$sExpectedOutput = "org\\tekuna\\core\\context\\Context: \n   ATest: 1234\n   AnotherTest: asdf\n";

			$this -> assertEquals($sExpectedOutput, $objContext -> __toString());
		}
	}
